package com.example.dakotanews.utils;

import com.example.dakotanews.entity.userInfo.JWTUserInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtUtil {

    // 用于签名JWT的密钥
    private final String SECRET_KEY = "Shadows";
    // JWT中存放的数据主体
    private final String CONTENT = "userInfo";

    /**
     * @description 将用户信息（部分）实体类转为json装入payload
     * @param userId 以用户ID（转换为String）作为JWT的subject
     * @param userDetails 用户信息（部分）实体类作为payload
     * @return 返回一个JWT
     */
    public String generateToken(Integer userId, JWTUserInfo userDetails) {
        Map<String, Object> claims = new HashMap<>();
        try {
            String userJson = new ObjectMapper().writeValueAsString(userDetails);
            claims.put(CONTENT, userJson);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return createToken(claims, String.valueOf(userId));
    }

    /**
     *
     * @param claims JWT中payload的声明部分，
     * @param subject JWT中的主题（作为JWT的标识）
     * @return 返回一个JWT字符串
     */
    private String createToken(Map<String, Object> claims, String subject) {

        // JWT的有效期。单位是毫秒
        int EXPIRATION_TIME = 1000 * 60 * 60 * 2;

        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    /**
     * @description 传递一个JWT解析其claims声明部分
     */
    private Claims extractAllClaims(String token) {
        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
    }

    /**
     * @description 获取JWT中的subject主题部分
     */
    public String extractSubject(String token) {
        return extractAllClaims(token).getSubject();
    }

    /**
     * @description 获取JWT中的指定claims声明，此处获取的是实体类的json数据因此需要转换回去
     */
    public JWTUserInfo extractJwtUserInfo(String token) {
        String userJson = extractAllClaims(token).get(CONTENT, String.class);
        try {
            return new ObjectMapper().readValue(userJson, JWTUserInfo.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @name JWT验证
     * @description 将jwt解析为用户ID，在解析中如果出现问题会返回一个空值而不是直接返回 400 错误
     * @param jwt 接受一个jwt作为参数，该值可以为空
     * @return 如果jwt为空或者解析过程中如果出现错误将返回一个空值，否则返回解析出来的用户ID
     */
    public Integer extractUserIdFromJWT(String jwt) {
        if(jwt == null || jwt.equals("")) {
            return null;
        } else {
            try {
                return Integer.parseInt(extractSubject(jwt));
            } catch (Exception e){
                return null;
            }
        }
    }

}
